package pyrachnid.model.scenar_model;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import pyrachnid.ctrl.Simulator;
import pyrachnid.ctrl.listener.listenerRobot;
import pyrachnid.model.ground_model.Cell;
import pyrachnid.model.ground_model.Map;
import pyrachnid.model.ground_model.Wind;
import pyrachnid.model.ground_model.Wind.Direction;
import pyrachnid.model.pathFinderModel.PathFind;
import pyrachnid.model.robot_model.Manager;
import pyrachnid.model.robot_model.Robot;
import pyrachnid.model.robot_model.RobotType;
import Event.Event;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class Scenario implements Cloneable {
	private String _name;
	private Map _map;
	private int _duration = 0;
	private Wind _wind;
	private Statistics _statistics;
	private int _speed ;
	private boolean _isInPause = false;
	private ArrayList<Robot> _robotList;
	private ArrayList<RobotType> _robotTypeList;

	private Manager _manager;
	private Simulator _simulator ;
	private String _mapPath;

	public Scenario(Simulator p_simulator) {
		
		_name = "scenar test";
		
		_wind = new Wind(Direction.SOUTH_EAST, 20);
		_robotList = new ArrayList<Robot>();
		_robotTypeList = new ArrayList<RobotType>();		

		_manager = Manager.getInstance();
		_manager.loadSenario(this);
		_simulator = p_simulator;
	         
		// TMP
	/*	_robotTypeList.add(new RobotType("Pattes", 155, 20, 500, new Astar(), "/images/maps/robot.gif"));
		_robotTypeList.add(new RobotType("Chenilles", 170, 30, 1000, new Astar(), "/images/maps/robot.gif"));
		_robotTypeList.add(new RobotType("Saucisse", 170, 10, 2000, new Astar(), "/images/maps/robot.gif"));*/
	
		//_robotList.add(new Robot(0, 1, _robotTypeList.get(0)));
		//_robotList.add(new Robot(3, 2, _robotTypeList.get(1)));
		//_robotList.add(new Robot(7, 7, _robotTypeList.get(2)));
		
		setSpeed(100);
		
	}
	
	@Override
	public Scenario clone() throws CloneNotSupportedException {
		Scenario clonedScenar = (Scenario) super.clone();
		
		if(_map != null)
			clonedScenar._map = _map.clone();
		
		clonedScenar._robotList = new ArrayList<Robot>();
		for(Robot robot : _robotList){
			clonedScenar._robotList.add(robot.clone());
		}
		
		clonedScenar._robotTypeList = new ArrayList<RobotType>();
		for(RobotType robotType : _robotTypeList){
			clonedScenar._robotTypeList.add(robotType.clone());
		}
		
		return clonedScenar;
	}



	public void loadImage(String p_path, int p_x, int p_y, String mapName) {
        BufferedImage myImage = null;
		try {
			myImage = ImageIO.read(new File(p_path));
		} catch (IOException e) {}

		setMapPath(p_path);
		_map = new Map(p_x, p_y, myImage, mapName);
		_manager.setMap(_map);
	}
	
	public boolean createRobotType(String pNameType, int pMaxGroundValue, int pGroundInfluence, double pExtinguishingSpeed, PathFind pPathFind, String pImagePath){
		return _robotTypeList.add(new RobotType(pNameType, pMaxGroundValue, pGroundInfluence, pExtinguishingSpeed, pPathFind, pImagePath));
	}

	public boolean addRobot(Robot robot) {
		robot.attach(new listenerRobot(_simulator, _simulator.getMainWindow()));
		return _robotList.add(robot);
	}

	public boolean deleteRobot(Robot p_robot) {
		return _robotList.remove(p_robot);
	}
	
	/**
	 * Delete from type robot list at the selected index
	 * @param p_index Index of the type robot in list
	 * @return Status of removal request
	 */
	public boolean removeRobotType(int p_index) {
		if(p_index < this._robotTypeList.size() && p_index >= 0) {
			this._robotTypeList.remove(p_index);
			return true;
		}
		return false;
	}

	public void setMap(Map map) {
		this._map = map;
		_manager.setMap(map);
	}

	public Map getMap() {
		return _map;
	}

	public void setWind(Wind wind) {
		this._wind = wind;
	}

	public Wind getWind() {
		return _wind;
	}

	public void setSpeed(int speed) {
		this._speed = speed;
		for(RobotType robotType : _robotTypeList)
			robotType.setDecressByTop(_speed);
	}

	public int getSpeed() {
		return _speed;
	}

	public void setInPause(boolean isInPause) {
		this._isInPause = isInPause;
		
		if(isInPause)
			_manager.start();
		else
			_manager.stop();
	}

	public boolean isInPause() {
		return _isInPause;
	}

	public ArrayList<Robot> getRobotList() {
		return _robotList;
	}
	
	public ArrayList<RobotType> getRobotTypeList() {
		return _robotTypeList;
	}
	
	public void addRobotType(RobotType robotType){
		_robotTypeList.add(robotType);
		robotType.setDecressByTop(_speed);
	}

	public void setStatistics(Statistics statistics) {
		this._statistics = statistics;
	}

	public Statistics getStatistics() {
		return _statistics;
	}

	public void setDuration(int duration) {
		this._duration = duration;
	}

	public int getDuration() {
		return _duration;
	}

	public void setName(String name) {
		this._name = name;
	}

	public String getName() {
		return _name;
	}
	
	public void setMapPath(String _mapPath) {
		this._mapPath = _mapPath;
	}

	public String getMapPath() {
		return _mapPath;
	}
	
	
	
	//Methode de sérialisation d'events liés à un Scenar
	//TODO Envisager peut être de déplacer ces methodes dans une class plus aproprié et au besoin la créer

	public void serializeEvent() {
		String aSerialiserRobot="";
		String aSerialiserCell="";
		String aSerialiserWind="";
		
		ArrayList<Cell> _cellList = _map.getCells();
		
		/*for(int i=0;i<_robotList.size();i++){
			aSerialiserRobot+=_roArrayList<Cell>botList.get(i).getSerializeEvent();
		}*/
		for(Robot robot : _robotList){
			aSerialiserRobot+=robot.getSerializeEvent();
		}
		aSerialiserRobot = aSerialiserRobot.replaceAll("<list>", "");
		aSerialiserRobot = aSerialiserRobot.replaceAll("</list>", "");
		
		for(int i=0;i<_cellList.size();i++){
			aSerialiserCell+=_cellList.get(i).getSerializeEvent();
		}
		
		aSerialiserCell = aSerialiserCell.replaceAll("<list>", "");
		aSerialiserCell = aSerialiserCell.replaceAll("</list>", "");
		
		aSerialiserWind = _wind.getSerializeEvent();
		aSerialiserWind = aSerialiserWind.replaceAll("<list>", "");
		aSerialiserWind = aSerialiserWind.replaceAll("</list>", "");
		
		FileWriter writer = null;
		
		try{
		     writer = new FileWriter("fichiersXML/listeEventRobot.xml", false);
		     writer.write("<list>"+aSerialiserRobot+"</list>");
		     writer.close();
		     
		     writer = new FileWriter("fichiersXML/listeEventCell.xml", false);
		     writer.write("<list>"+aSerialiserCell+"</list>");
		     writer.close();
		     
		     writer = new FileWriter("fichiersXML/listeEventWind.xml", false);
		     writer.write("<list>"+aSerialiserWind+"</list>");
		     writer.close();
		     
		}catch(IOException ex){
		    ex.printStackTrace();
		
		}
			   
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<Event> getSerializeEventRobot() throws FileNotFoundException{
		  // Instanciation de la classe XStream
      XStream xstream = new XStream(new DomDriver());
      File unFichier = new File("fichiersXML/listeEventRobot.xml");
      ArrayList<Event> nouvelListeEvent = new ArrayList<Event>();
      // Redirection du fichier listeEventRobot.xml vers un flux
      // d'entr�e fichier
      if(unFichier.exists()){
	      FileInputStream fis = new FileInputStream(new File("fichiersXML/listeEventRobot.xml"));	      
	      try {
	          // D�s�rialisation du fichier listeEventRobot.xml vers un nouvel
	          // objet article
	    	  nouvelListeEvent = (ArrayList<Event>) xstream.fromXML(fis);
	    	  //System.out.println("Nombre d'event dans robot : "+nouvelListeEvent.size());
	          fis.close();
	      } catch (IOException e) {
			// TODO Bloc catch auto-g�n�r�
			e.printStackTrace();
		}
      }
      
      return nouvelListeEvent;
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<Event> getSerializeEventCell() throws FileNotFoundException{
		  // Instanciation de la classe XStream
      XStream xstream = new XStream(new DomDriver());
      File unFichier = new File("fichiersXML/listeEventCell.xml");
      ArrayList<Event> nouvelListeEvent = new ArrayList<Event>();
      // Redirection du fichier listeEventCell.xml vers un flux
      // d'entr�e fichier
      if(unFichier.exists()){
    	  FileInputStream fis = new FileInputStream(unFichier);      
	      try {
	          // D�s�rialisation du fichier listeEventCell.xml vers un nouvel
	          // objet article
	    	  nouvelListeEvent = (ArrayList<Event>) xstream.fromXML(fis);          
	    	  //System.out.println("Nombre d'event dans Cell : "+nouvelListeEvent.size());
	          fis.close();
	      } catch (IOException e) {
			// TODO Bloc catch auto-g�n�r�
			e.printStackTrace();
	      }
	}      
      return nouvelListeEvent;
	}
	
	@SuppressWarnings("unchecked")
	public ArrayList<Event> getSerializeEventWind() throws FileNotFoundException{
		  // Instanciation de la classe XStream
      XStream xstream = new XStream(new DomDriver());
      ArrayList<Event> nouvelListeEvent = new ArrayList<Event>();
      File unFichier = new File("fichiersXML/listeEventWind.xml");
      // Redirection du fichier listeEventCell.xml vers un flux
      // d'entr�e fichier
      if(unFichier.exists()){
	      FileInputStream fis = new FileInputStream(unFichier);
	      
	      try {
	          // D�s�rialisation du fichier listeEventCell.xml vers un nouvel
	          // objet article
	    	  nouvelListeEvent = (ArrayList<Event>) xstream.fromXML(fis);          
	    	  //System.out.println("Nombre d'event dans Wind : "+nouvelListeEvent.size());
	          fis.close();
	      } catch (IOException e) {
			// TODO Bloc catch auto-g�n�r�
			e.printStackTrace();
		}
      }
      
      return nouvelListeEvent;
	}
}
